﻿#pragma once


#include "Pages/EditorPageViewModel.h"
#include "EditorTextFilePageModel.h"
#include "Math/Color.h"
#include "Event/TextInputEvent.h"
#include "Framework/Tickable.h"
#include "Widgets/Widget.h"
#include "Widgets/CanvasWidget.h"
#include "Document/PieceTable.h"
#include "EditorTextFilePageViewModel.m.h"


class RFont;
class REditorScriptFile;

RCLASS(ExtraHeader= ["Language/EditorScriptFile.h"]) 
class REditorTextFilePageViewModel : public REditorPageViewModel , public ITickable
{
    ROBJECT

public:
    void BindModel(TSharedObjectPtr<REditorPageModel> InModel) override;
    TSharedObjectPtr<RTexture2D> GetIcon() const override;
    CString GetTitle() const override;

protected:
    TSharedObjectPtr<RTexture2D> Icon;
    TWeakObjectPtr<REditorTextFilePageModel> Model;

public:


    float GetLineHeight() const;
    float GetLineNumberTextWidth() const;
    SColor GetLineNumberTextColor(int64_t InVisibleLineIndex) const;
    TSharedObjectPtr<RFont> GetFont() const
    {
        return Font;
    }
    int64_t GetFontSize() const
    {
        return FontSize;
    }
    
    const float CodeAreaLeftOffset = 90.0f;

    //base 0
    int64_t GetLineIndex(int64_t InVisibleLineIndex) const;

    CString GetTextOfRange(
        int64_t InStartVisibleLineIndex, 
        int64_t InEndVisibleLineIndex, 
        int64_t & OutStartCharIndex ,
        int64_t & OutEndCharIndex //inclusive
        ) const;

    TVector<SColorfulTextColor> GetTextColorsOfRange(
        int64_t InStartCharIndex, 
        int64_t InEndCharIndex //inclusive
    ) const;

    //base 0
    CString GetLineContent(int64_t InVisibleLineIndex) const;

    // ITickable interface
    // make cursor blink
    void Tick(float DeltaSeconds)override;
    bool ShouldShowCursor() const;
    void StartEdit(RWidgetWeakPtr InContentAreaWidget);
    void EndEdit();
    //base 0
    int64_t GetCursorLineIndex() const;
    //base 0
    int64_t GetCursorColumnIndex() const;
    void SetCursorLineIndex(int64_t InLineIndex);
    void SetCursorColumnIndex(int64_t InColumnIndex);
    bool OnTextInput(const STextInputEvent& InEvent);
    bool OnKeyboardEvent(const SKeyboardEvent& InKeyboardEvent);

    SDocumentPosition CalculateCursorPosition(SVec2 RelativeMouseArea);


    const float TextContentThumbnailWidth = 150.f;
    bool HasTextRanderer() const
    {
        return TextRanderer.IsValid();
    }
    const TVector<SColorfulTextColor>& GetTextColors() const;
    CString GetWholeText() const;
    const int64_t ThumbnailFontSize=2;


    const float VerticalScrollBarWidth = 20.0f;
    float GetContentAreaYOffset() const;

    //if  return 0,scrollbar is invisible
    struct SVerticleScrollBarPositionAndHeight
    {
        float Position;
        float Height;
    };
    SVerticleScrollBarPositionAndHeight GetVerticalScrollbarPositionAndHeight(float VisibleAreaHeight) const;
    
    /// @brief update the vertical scrollbar percent
    /// @param InVisibleAreaHeight 
    /// @param RelativeMouseY  Mouse Y relative to the top of the visible area
    void UpdateVerticalScrollbarPercent(float InVisibleAreaHeight,float RelativeMouseY);

protected:
    int64_t GetDocumentLineCount() const;

    TSharedObjectPtr<RFont> Font;
    int64_t FontSize = 16;
    int64_t LineHeight; //calculated from font size and font

    bool CursorShowState = true;
    float ElapsedTime = 0.0f;
    const float CursorBlinkInterval = 0.5f;

    //可能为空
    //普通的文本没有染色器
    TWeakObjectPtr<REditorScriptFile> TextRanderer;

public:


    SColor GetDisabledDebugPointColor();
    SColor GetBreakpointColor();
    SColor GetAddingBreakpointColor();

    enum class EDebugPointType
    {
        None,
        Normal,
        Disabled,
        Adding, //mouse is hovering on the line
    }; 

    EDebugPointType GetDebugPointType(int64_t InVisibleLineIndex) const;

    void HovorLineNumber(SVec2 RelativeMouseArea);
    void ClearHoverLineNumber();

    //add or remove breakpoint
    void AddOrRemoveBreakpoint(SVec2 RelativeMouseArea);
protected:
    int64_t HoveringVisibleLineIndex = -1;

    //is continous move cursor vertically
    bool IsVerticalMoveCursor= false;
    int64_t CursorColumnBeforeVerticalMove = 0;

public:

    //当前是否有选中的文本
    bool HasSelection() const
    {
        return SelectionStart!=SelectionEnd;
    }
    //选中的文本的开始和结束位置，这两个位置可能需要交换
    SDocumentPosition SelectionStart;
    SDocumentPosition SelectionEnd;

    CString GetSelectedText() const;

    virtual bool Cut() override;
    virtual bool Copy() override;
    virtual bool Paste() override;
    virtual bool CanCut() const override;
    virtual bool CanCopy() const override;
    virtual bool CanPaste() const override;
    virtual void PostUndo() override;
    virtual void PostRedo() override;

    struct SHighlightRange
    {
        int32_t StartLineIndex;
        int32_t StartColumnIndex;

        int32_t EndLineIndex;
        int32_t EndColumnIndex;

        SColor Color;
    };

    TVector<SHighlightRange> GetHighlightRanges() const;
protected:
    void CreateSelectionHighlightRange(TVector<SHighlightRange> & InOutHighlightRanges) const;
public:
    void UpdateVisibleLineRange(const SVec2 & InVisibleAreaSize);
    int64_t GetMinVisibleLine() const
    {
        return MinVisibleLine;
    }
    int64_t GetMaxVisibleLine() const
    {
        return MaxVisibleLine;
    }
protected:
    //可见文本的最小行和最大行,在这个范围内的文本才会被渲染
    //在获取这个范围之前，需要先调用UpdateVisibleLineRange以更新这个范围
    int64_t MinVisibleLine=-1;
    int64_t MaxVisibleLine=-1;

    //页面滚动到指定位置
    void ScrollTo(const SDocumentPosition& InPosition);

//搜索和替换相关
public:
    void SearchText(const CString& InSearchText);
    //清除搜索结果，和搜索文本，恢复到没有搜索的状态
    void ClearSearch();
    int64_t GetSearchResultCount() const;
    //可以为-1
    int64_t GetCurrentSearchIndex() const;
    void GotoNextMatched();
    void GotoPreviousMatched();
protected:
    //搜索结果
    struct SearchResult
    {
        SDocumentPosition Start; //包含
        SDocumentPosition End; //不包含
        SDocumentPosition InclusiveEnd; //包含
    };

    //搜索文本，返回所有匹配的位置
    TVector<SearchResult> SearchTextImplement(const CString& InSearchText) const;
    void UpdateSearchIndex();
    CString TextForSearch;

    TVector<SearchResult> SearchResults;

    //当前搜索结果的索引
    //为-1时表示光标不在任何搜索结果处
    int64_t CurrentSearchIndex = -1;

//替换相关
public:
    void Replace(const CString& InNewText);
    void ReplaceAll(const CString& InNewText);

    void PostUserChangedText();
};
